from logging import getLogger
import re




log = getLogger('meercat.mapreduce.reducers.utils')

def setReduction(values):
    #log.debug('setReduction(%s)' % (unicode(values)))
    return frozenset(filter(lambda x: x,values))

def insensitiveSetReduction(values):
    #log.debug('insensitiveSetReduction(%s)' % (unicode(values)))
    return frozenset(map(lambda x:x.title(),filter(lambda x: x,values)))

def firstValue(values):
    log.debug('firstValue(%s)' % (str(values),))
    values = filter(lambda x: x,values)
    if len(values) > 0:
        return [values[0]]
    
    return []

def integerSum(values):
    return [str(sum(map(int,values),0))]

_yearExpression = re.compile('(\d{4})')
def firstYear(values):
    values = extractYears(values)
    
    if not values or len(values) < 1:
        return []
    
    value = min(values)
    
    if value:
        return [str(value)]
    
    return []
    
def extractYears(values):
    return setReduction(sum(map(_yearExpression.findall,
                                filter(lambda v: v,values)),[]))

class requiredMap(object):
    def __init__(self, _map):
        self._map = _map
    
    def __call__(self, values):
        return setReduction(map(self._map.get,
                                filter(self._map.has_key,values)))

class optionalMap(object):
    def __init__(self, _map):
        self._map = _map
    
    def __call__(self, values):
        return setReduction(map(lambda x: x in self._map and 
                                self._map[x] or x,values))

class filteredOptionalMap(optionalMap):
    def __init__(self, _map, _filter):
        assert callable(_filter)
        self._filter = _filter
        self._map = _map
    
    def __call__(self, values):
        return filter(self._filter,
                      super(filteredOptionalMap, self).__call__(values))